import { ModelCtor, Model, Includeable } from "sequelize";
import { Context } from "egg";
import * as uuid from "uuid";
import helper from "../helper";

/**
 * 基础数据库操作
 */
export default class EntityDao {
  public ctx: Context;

  /**
   * 模型
   */
  public model: ModelCtor<Model<any, any>>;

  /**
   * 关联模型配置
   */
  public include: Includeable[] = [];

  constructor(ctx: Context, model: ModelCtor<Model<any, any>>, include: Includeable[] = []) {
    this.ctx = ctx;
    this.model = model;
    this.include = include;
  }

  /**
   * 向数据库中新增模型
   * @param model ctx.model.XXXX
   * @param data 数据
   * @param fields 需要非空校验的字段
   * @returns
   */
  async create(data: any, fields: string[] = []): Promise<ServiceResponse> {
    let resp: ServiceResponse;
    try {
      const result = helper.modelValidate(data, fields);
      if (!result.success) {
        resp = {
          body: helper.fail(result.message),
          status: 500
        };
      } else {
        const entity: any = { ...data };
        // 自动插入唯一uuid
        entity[this.model.primaryKeyAttribute] = uuid.v1().replace(/-/g, "").toUpperCase();
        const domain = (await this.model.create(entity)) as any;

        resp = {
          body: helper.success(domain[this.model.primaryKeyAttribute]),
          status: 200
        };
      }
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }

  /**
   * 删除指定数据
   * @param model 模型
   * @param pk 数据主键Id
   * @returns
   */
  async destroy(pk: string | number) {
    let resp: any;
    try {
      const where: any = {};
      where[this.model.primaryKeyAttribute] = pk;
      await this.model.destroy({ where });
      resp = {
        body: helper.success(pk),
        status: 200
      };
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }

  /**
   * 修改模型
   * @param model 模型
   * @param pk 主键
   * @param data 修改数据
   * @param fields 非空字段集合
   * @returns
   */
  async update(pk: string | number, data: any, fields: string[] = []) {
    let resp: ServiceResponse;
    try {
      const result = helper.modelValidate(data, fields);
      if (!result.success) {
        resp = {
          body: helper.fail(result.message),
          status: 500
        };
      } else {
        const where: any = {};
        where[this.model.primaryKeyAttribute] = pk;
        const result: [number] = (await this.model.update(data, { where })) as any;
        if (result[0] < 1) {
          resp = {
            body: helper.fail("数据不存在"),
            status: 500
          };
        } else {
          resp = {
            body: helper.success(pk),
            status: 200
          };
        }
      }
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }

  /**
   * 查询模型列表，根据创建时间倒序排列
   * @param model 模型
   * @param where 符合sequelize规范的查询条件
   */
  async index(where: any = {}) {
    let resp: ServiceResponse;
    try {
      const domains = (await this.model.findAll({ order: [["createdAt", "DESC"]], where, include: this.include })) as any;
      resp = {
        body: helper.success(domains),
        status: 200
      };
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }

  /**
   * 查询数据明细
   * @param model 模型
   * @param pk 主键
   * @returns
   */
  async show(pk: string | number) {
    let resp: ServiceResponse;
    try {
      const where: any = {};
      where[this.model.primaryKeyAttribute] = pk;
      const domain = (await this.model.findOne({ where, include: this.include })) as any;
      if (domain) {
        resp = {
          body: helper.success(domain),
          status: 200
        };
      } else {
        resp = {
          body: helper.fail("数据不存在"),
          status: 500
        };
      }
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }

  /**
   * 模型分页查询，根据创建时间倒序排列
   * @param model 模型
   * @param options.currernt 当前页
   * @param options.pageSize 每页条数
   * @param options.where 符合sequelize规范的查询条件
   * @param options.include 关联查询条件
   * @returns
   */
  async page(options: { current: string; pageSize: string; where: any }) {
    let resp: ServiceResponse;
    try {
      const result = helper.modelValidate(options, ["current", "pageSize"]);
      if (!result.success) {
        resp = {
          body: helper.fail(result.message),
          status: 500
        };
      } else {
        const pageSize = Number(options.pageSize);
        const current = Number(options.current);

        const domains = (await this.model.findAll({
          order: [["createdAt", "DESC"]],
          where: options.where,
          limit: pageSize - 0,
          offset: (current - 1) * (pageSize - 1),
          include: this.include
        })) as any;
        const total = await this.model.count({
          where: options.where
        });
        resp = {
          body: helper.success({ total, current, pageSize, records: domains }),
          status: 200
        };
      }
    } catch (error) {
      resp = {
        body: helper.fail(error.message),
        status: 500
      };
    }
    return resp;
  }
}
